Example #1
0
        public void Parse()
        {
            var index = clang.createIndex(0, 1);
            var args  = new string[]
            {
                "-x",
                "c++"
            };

            // prepare input file
            // comment out existing includes
            // append required typedefs
            var hdr = CommonTypes.Append(File.ReadAllText(FileName).Replace("#include", "//#include")).ToString();

            var unsavedFiles = new CXUnsavedFile[]
            {
                new CXUnsavedFile()
                {
                    Contents = hdr,
                    Filename = FileName,
                    Length   = hdr.Length
                }
            };

            CXTranslationUnit translationUnit;
            var result = parseTranslationUnit2(index, FileName, args, args.Length, unsavedFiles, (uint)unsavedFiles.Length, (uint)CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies, out translationUnit);

            if (result != CXErrorCode.CXError_Success)
            {
                return;
            }

            clang.visitChildren(clang.getTranslationUnitCursor(translationUnit), VisitStruct, new CXClientData(IntPtr.Zero));
        }
Example #2
0
        protected static TranslationUnit CreateTranslationUnit(string inputContents)
        {
            Assert.True(File.Exists(DefaultInputFileName));

            using var unsavedFile = CXUnsavedFile.Create(DefaultInputFileName, inputContents);
            var unsavedFiles = new CXUnsavedFile[] { unsavedFile };

            var index           = CXIndex.Create();
            var translationUnit = CXTranslationUnit.Parse(index, DefaultInputFileName, DefaultClangCommandLineArgs, unsavedFiles, DefaultTranslationUnitFlags);

            if (translationUnit.NumDiagnostics != 0)
            {
                var errorDiagnostics = new StringBuilder();
                _ = errorDiagnostics.AppendLine($"The provided {nameof(CXTranslationUnit)} has the following diagnostics which prevent its use:");
                var invalidTranslationUnitHandle = false;

                for (uint i = 0; i < translationUnit.NumDiagnostics; ++i)
                {
                    using var diagnostic = translationUnit.GetDiagnostic(i);

                    if (diagnostic.Severity is CXDiagnosticSeverity.CXDiagnostic_Error or CXDiagnosticSeverity.CXDiagnostic_Fatal)
                    {
                        invalidTranslationUnitHandle = true;
                        _ = errorDiagnostics.Append(' ', 4);
                        _ = errorDiagnostics.AppendLine(diagnostic.Format(CXDiagnosticDisplayOptions.CXDiagnostic_DisplayOption).ToString());
                    }
                }

                Assert.False(invalidTranslationUnitHandle, errorDiagnostics.ToString());
            }

            return(TranslationUnit.GetOrCreate(translationUnit));
        }
        private async Task ValidateGeneratedBindingsAsync(string inputContents, string expectedOutputContents, PInvokeGeneratorConfigurationOptions configOptions, string[] excludedNames, IReadOnlyDictionary <string, string> remappedNames, IReadOnlyDictionary <string, IReadOnlyList <string> > withAttributes, IReadOnlyDictionary <string, string> withCallConvs, IReadOnlyDictionary <string, string> withLibraryPaths, string[] withSetLastErrors, IReadOnlyDictionary <string, string> withTypes, IReadOnlyDictionary <string, IReadOnlyList <string> > withUsings, IEnumerable <Diagnostic> expectedDiagnostics, string libraryPath)
        {
            Assert.True(File.Exists(DefaultInputFileName));

            using var outputStream = new MemoryStream();
            using var unsavedFile  = CXUnsavedFile.Create(DefaultInputFileName, inputContents);

            var unsavedFiles = new CXUnsavedFile[] { unsavedFile };
            var config       = new PInvokeGeneratorConfiguration(libraryPath, DefaultNamespaceName, Path.GetRandomFileName(), testOutputLocation: null, configOptions, excludedNames, headerFile: null, methodClassName: null, methodPrefixToStrip: null, remappedNames, traversalNames: null, withAttributes, withCallConvs, withLibraryPaths, withSetLastErrors, withTypes, withUsings);

            using (var pinvokeGenerator = new PInvokeGenerator(config, (path) => outputStream))
            {
                var handle = CXTranslationUnit.Parse(pinvokeGenerator.IndexHandle, DefaultInputFileName, DefaultClangCommandLineArgs, unsavedFiles, DefaultTranslationUnitFlags);
                using var translationUnit = TranslationUnit.GetOrCreate(handle);

                pinvokeGenerator.GenerateBindings(translationUnit);

                if (expectedDiagnostics is null)
                {
                    Assert.Empty(pinvokeGenerator.Diagnostics);
                }
                else
                {
                    Assert.Equal(expectedDiagnostics, pinvokeGenerator.Diagnostics);
                }
            }
            outputStream.Position = 0;

            var actualOutputContents = await new StreamReader(outputStream).ReadToEndAsync();

            Assert.Equal(expectedOutputContents, actualOutputContents);
        }
Example #4
0
    public void Run(string[] args, CodeBuilder result)
    {
        ParseCommandLineArgs(args, out var commandLineArgs, out var sourceContents);

        using (var unsavedFile = CXUnsavedFile.Create("Source", sourceContents))
            using (var index = Index.Create(false, true))
            {
                var unsavedFiles = new CXUnsavedFile[] { unsavedFile };

                var handle = CXTranslationUnit.Parse(
                    index.Handle,
                    unsavedFile.FilenameString,
                    commandLineArgs,
                    unsavedFiles,
                    CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes    // Include attributed types in CXType
                    | CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes // Implicit attributes should be visited
                    | CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies
                    );

                var translationUnit = TranslationUnit.GetOrCreate(handle);

                CheckTranslationUnitErrors(translationUnit, sourceContents);
                VisitTranslationUnit(translationUnit);
            }

        WriteNamespace(result);
    }
Example #5
0
 internal unsafe static extern CXCodeCompleteResults* clang_codeCompleteAt(CXTranslationUnit tu,
                                                                         string filename,
                                                                         uint line,
                                                                         uint column,
                                                                         CXUnsavedFile[] unsavedFiles,
                                                                         uint num_unsaved_files,
                                                                         uint options);
        public List <CXUnsavedFile> Get()
        {
            var unsavedFiles = new List <CXUnsavedFile> ();

            foreach (var unsaved in UnsavedFileCollection)
            {
                if (unsaved.Value.IsDirty)
                {
                    CXUnsavedFile unsavedFile = new CXUnsavedFile();
                    unsavedFile.Initialize(unsaved.Key, unsaved.Value.Text, Project.ClangManager.IsBomPresentInFile(unsaved.Key));
                    unsavedFiles.Add(unsavedFile);
                }
            }
            return(unsavedFiles);
        }
        private CXTranslationUnit?ParseHeader(string header, out CXUnsavedFile[] unsaved, int bits)
        {
            var args = new[] {
                "-x", "c-header", $"-m{bits}"
            };

            unsaved = new CXUnsavedFile[0];
            var error = clang.parseTranslationUnit2(
                bits == 32
                                        ? ClangIndex32
                                        : bits == 64
                                                ? ClangIndex64
                                                : throw new NotImplementedException(),
                header,
                args, args.Length,
                unsaved, 0,
                0, out CXTranslationUnit unit);

            var success = error == CXErrorCode.CXError_Success;

            if (success)
            {
                return(unit);
            }


            var numDiagnostics = clang.getNumDiagnostics(unit);

            ICollection <string> diagMsgs = new LinkedList <string>();

            for (uint i = 0; i < numDiagnostics; ++i)
            {
                var diagnostic = clang.getDiagnostic(unit, i);
                diagMsgs.Add(clang.getDiagnosticSpelling(diagnostic).ToString());
                clang.disposeDiagnostic(diagnostic);
            }

            throw new InvalidProgramException($"Clang {error} parsing {header} for {bits}-bit")
                  {
                      Data =
                      {
                          { nameof(error),    error    },
                          { nameof(header),   header   },
                          { nameof(bits),     bits     },
                          { nameof(diagMsgs), diagMsgs }
                      }
                  };
        }
Example #8
0
        public AST ParseWithClangArgs(CppConfig config)
        {
            if (config.Sources.Count == 0)
            {
                Console.WriteLine("No input sources or includes");
                return(null);
            }

            // the index object
            CXIndex Index = clang.createIndex(0, 0);

            // prepare some vars for parse
            uint option = clang.defaultEditingTranslationUnitOptions()
                          | (uint)CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;
            CXUnsavedFile unsavedFile = new CXUnsavedFile();

            CXTranslationUnit TU;
            var error = clang.parseTranslationUnit2(Index, config.Sources[0], config.Extras, config.Extras.Length, out unsavedFile, 0,
                                                    option, out TU);

            if (error != CXErrorCode.CXError_Success)
            {
                Console.WriteLine("Failed to parse Translation Unit!");
                return(null);
            }

            bool fatal          = false;
            var  numDiagnostics = clang.getNumDiagnostics(TU);

            for (uint loop = 0; loop < numDiagnostics; ++loop)
            {
                fatal |= DealingWithDiagnostic(clang.getDiagnostic(TU, loop));
            }
            if (fatal)
            {
                return(null);
            }

            ASTVisitor visitor = new ASTVisitor();
            AST        ast     = visitor.Visit(TU);

            clang.disposeIndex(Index);
            return(ast);
        }
Example #9
0
        public static void Main(string[] args)
        {
            Regex re = new Regex(@"(?<switch>-{1,2}\S*)(?:[=:]?|\s+)(?<value>[^-\s].*?)?(?=\s+[-]|$)");
            List <KeyValuePair <string, string> > matches = (from match in re.Matches(string.Join(" ", args)).Cast <Match>()
                                                             select new KeyValuePair <string, string>(match.Groups["switch"].Value, match.Groups["value"].Value))
                                                            .ToList();

            var    files            = new List <string>();
            var    includeDirs      = new List <string>();
            string outputFile       = string.Empty;
            string @namespace       = string.Empty;
            string libraryPath      = string.Empty;
            string prefixStrip      = string.Empty;
            string methodClassName  = "Methods";
            string excludeFunctions = "";

            string[] excludeFunctionsArray = null;

            foreach (KeyValuePair <string, string> match in matches)
            {
                if (string.Equals(match.Key, "--n") || string.Equals(match.Key, "--namespace"))
                {
                    @namespace = match.Value;
                }

                if (string.Equals(match.Key, "--l") || string.Equals(match.Key, "--libraryPath"))
                {
                    libraryPath = match.Value;
                }

                if (string.Equals(match.Key, "--i") || string.Equals(match.Key, "--include"))
                {
                    includeDirs.Add(match.Value);
                }

                if (string.Equals(match.Key, "--o") || string.Equals(match.Key, "--output"))
                {
                    outputFile = match.Value;
                }

                if (string.Equals(match.Key, "--f") || string.Equals(match.Key, "--file"))
                {
                    files.Add(match.Value);
                }

                if (string.Equals(match.Key, "--p") || string.Equals(match.Key, "--prefixStrip"))
                {
                    prefixStrip = match.Value;
                }

                if (string.Equals(match.Key, "--m") || string.Equals(match.Key, "--methodClassName"))
                {
                    methodClassName = match.Value;
                }

                if (string.Equals(match.Key, "--e") || string.Equals(match.Key, "--excludeFunctions"))
                {
                    excludeFunctions = match.Value;
                }
            }

            var errorList = new List <string>();

            if (!files.Any())
            {
                errorList.Add("Error: No input C/C++ files provided. Use --file or --f");
            }

            if (string.IsNullOrWhiteSpace(@namespace))
            {
                errorList.Add("Error: No namespace provided. Use --namespace or --n");
            }

            if (string.IsNullOrWhiteSpace(outputFile))
            {
                errorList.Add("Error: No output file location provided. Use --output or --o");
            }

            if (string.IsNullOrWhiteSpace(libraryPath))
            {
                errorList.Add("Error: No library path location provided. Use --libraryPath or --l");
            }

            if (errorList.Any())
            {
                Console.WriteLine("Usage: ClangPInvokeGenerator --file [fileLocation] --libraryPath [library.dll] --output [output.cs] --namespace [Namespace] --include [headerFileIncludeDirs] --excludeFunctions [func1,func2]");
                foreach (var error in errorList)
                {
                    Console.WriteLine(error);
                }
            }

            if (!string.IsNullOrEmpty(excludeFunctions))
            {
                excludeFunctionsArray = excludeFunctions.Split(',').Select(x => x.Trim()).ToArray();
            }

            var createIndex = clang.createIndex(0, 0);

            string[] arr = { "-x", "c++" };

            arr = arr.Concat(includeDirs.Select(x => "-I" + x)).ToArray();

            List <CXTranslationUnit> translationUnits = new List <CXTranslationUnit>();

            foreach (var file in files)
            {
                CXTranslationUnit translationUnit;
                CXUnsavedFile[]   unsavedFile = new CXUnsavedFile[0];
                var translationUnitError      = clang.parseTranslationUnit2(createIndex, file, arr, 3, unsavedFile, 0, 0, out translationUnit);

                if (translationUnitError != CXErrorCode.CXError_Success)
                {
                    Console.WriteLine("Error: " + translationUnitError);
                    var numDiagnostics = clang.getNumDiagnostics(translationUnit);

                    for (uint i = 0; i < numDiagnostics; ++i)
                    {
                        var diagnostic = clang.getDiagnostic(translationUnit, i);
                        Console.WriteLine(clang.getDiagnosticSpelling(diagnostic).ToString());
                        clang.disposeDiagnostic(diagnostic);
                    }
                }

                translationUnits.Add(translationUnit);
            }

            using (var sw = new StreamWriter(outputFile))
            {
                sw.NewLine = "\n";

                sw.WriteLine("namespace " + @namespace);
                sw.WriteLine("{");

                sw.WriteLine("    using System;");
                sw.WriteLine("    using System.Runtime.InteropServices;");
                sw.WriteLine();

                var structVisitor = new StructVisitor(sw);
                foreach (var tu in translationUnits)
                {
                    clang.visitChildren(clang.getTranslationUnitCursor(tu), structVisitor.Visit, new CXClientData(IntPtr.Zero));
                }

                var typeDefVisitor = new TypeDefVisitor(sw);
                foreach (var tu in translationUnits)
                {
                    clang.visitChildren(clang.getTranslationUnitCursor(tu), typeDefVisitor.Visit, new CXClientData(IntPtr.Zero));
                }

                var enumVisitor = new EnumVisitor(sw);
                foreach (var tu in translationUnits)
                {
                    clang.visitChildren(clang.getTranslationUnitCursor(tu), enumVisitor.Visit, new CXClientData(IntPtr.Zero));
                }

                sw.WriteLine("    public static partial class " + methodClassName);
                sw.WriteLine("    {");
                {
                    var functionVisitor = new FunctionVisitor(sw, libraryPath, prefixStrip, excludeFunctionsArray);
                    foreach (var tu in translationUnits)
                    {
                        clang.visitChildren(clang.getTranslationUnitCursor(tu), functionVisitor.Visit, new CXClientData(IntPtr.Zero));
                    }
                }
                sw.WriteLine("    }");
                sw.WriteLine("}");
            }

            foreach (var tu in translationUnits)
            {
                clang.disposeTranslationUnit(tu);
            }

            clang.disposeIndex(createIndex);
        }
Example #10
0
        /// <summary>
        /// Build the Clang AST
        /// </summary>
        private TranslationUnit BuildClangAST(Configuration config, CXIndex index)
        {
            CXTranslationUnit tu = null;

            using (var section = CreateSection("Building Clang AST"))
            {
                // Assemble the arguments
                var clangArgs = new List <string>()
                {
                    "-Wno-pragma-once-outside-header"
                };

                switch (config.Clang.Language)
                {
                case LanguageEnum.C99:
                    clangArgs.Add("-xc");
                    clangArgs.Add("-std=c99");
                    break;

                case LanguageEnum.Cpp11:
                    clangArgs.Add("-xc++");
                    clangArgs.Add("-std=c++11");
                    break;

                case LanguageEnum.Cpp14:
                    clangArgs.Add("-xc++");
                    clangArgs.Add("-std=c++14");
                    break;

                case LanguageEnum.Cpp17:
                    clangArgs.Add("-xc++");
                    clangArgs.Add("-std=c++17");
                    break;

                default:
                    throw new Exception($"unknown language {config.Clang.Language}");
                }

                clangArgs.AddRange(GetWinSDKDIncludeArgs(config));
                clangArgs.AddRange(GetCxxSTLIncludeArgs(config));

                clangArgs.AddRange(config.Clang.Includes.Select(i => MakeIncludeArg(i)));
                clangArgs.AddRange(config.Clang.Defines.Select((m, v) => $"-D{m}=\"{v}\""));
                clangArgs.AddRange(config.Clang.Arguments.Split(" "));

                var tuFlags = CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;

                // Create the TU source file
                var sourceFiles = new HashSet <string>();
                config.Hook.Descriptions.Values.ToList().ForEach(hook => hook.Input.ForEach(source => sourceFiles.Add(source)));

                var tuFilename = Path.GetFileNameWithoutExtension(string.IsNullOrEmpty(config.Plugin.Name) ? Path.GetTempFileName() : config.Plugin.Name) + ".cpp";
                Logger.Debug($"Clang TU filename: {tuFilename}");

                var tuSource = "#include <" + string.Join(">\n#include <", sourceFiles) + ">";

                Logger.Debug($"Clang TU source:\n  {tuSource.Replace("\n", "\n  ")}");
                using (var tuSourceFile = CXUnsavedFile.Create(tuFilename, tuSource))
                {
                    // Invoke clang to get the TU
                    Logger.Debug($"Clang args: {string.Join(" ", clangArgs)}");
                    var tuError = CXTranslationUnit.TryParse(index, tuSourceFile.FilenameString, clangArgs.ToArray(), new CXUnsavedFile[] { tuSourceFile }, tuFlags, out tu);
                    if (tuError != CXErrorCode.CXError_Success)
                    {
                        throw new Exception($"clang error: failed to generate tanslation unit: {tuError}");
                    }
                }
                section.Done();
            }
            if (tu == null)
            {
                return(null);
            }
            return(TranslationUnit.GetOrCreate(tu));
        }
Example #11
0
        public void Parse(string sourceFile, string[] includeDirs = null, string[] additionalOptions = null, bool msCompati = true)
        {
            var file = _EntityBinder.File(sourceFile);

            if (_TranslationUnits.ContainsKey(file))
            {
                return;
            }

            var ufile   = new CXUnsavedFile();
            var tu      = new CXTranslationUnit();
            var options = new List <string>(new string[] { "-std=c++14", "-ferror-limit=9999" });

            if (includeDirs != null)
            {
                foreach (var dir in includeDirs)
                {
                    options.Add(string.Concat("-I", dir, ""));
                }
            }

            if (additionalOptions != null)
            {
                options.AddRange(additionalOptions);
            }

            if (msCompati)
            {
                options.Add("-fms-extensions");
                options.Add("-fms-compatibility");
            }

            var erro = clang.parseTranslationUnit2(_Index, sourceFile, options.ToArray(), options.Count, out ufile, 0, 0, out tu);

            _CurrentTranslation             = new Translation(tu, file);
            _CurrentTranslation.Diagnostics = Diagnostic.CreateFrom(tu);
            _TranslationUnits[file]         = _CurrentTranslation;

            foreach (var d in _CurrentTranslation.Diagnostics)
            {
                _Output.AppendLine(d.ToString());
            }


            // 本当はここでエラーチェックが好ましい
            var cursor = clang.getTranslationUnitCursor(tu);


            clang.visitChildren(cursor, _CursorVisitor, new CXClientData());


            //foreach(var e in new List<Entity>(_CursorToEntity.Values)) {
            //	Console.WriteLine(e.FullName);
            //}

            // TODO: 削除する
            var kinds = new List <CXCursorKind>(_UsedKinds);

            kinds.Sort();
            foreach (var kind in kinds)
            {
                Console.WriteLine(kind);
            }
        }
Example #12
0
        static ClangTU Parse(
            IReadOnlyList <string> args,
            string filename,
            string unsaved)
        {
            var index = libclang.clang_createIndex(0, 1);

            if (index == IntPtr.Zero)
            {
                return(null);
            }

            // args
            var buffers = args.Select(x => AllocBuffer.FromString(x)).ToArray();
            var ptrs    = buffers.Select(x => x.Ptr).ToArray();

            var options = (uint)CXTranslationUnit_Flags._DetailedPreprocessingRecord
                          // | CXTranslationUnit_SkipFunctionBodies
            ;

            var filenameBytes = Encoding.UTF8.GetBytes(filename).Concat(new byte[] { 0 }).ToArray();

            List <Action> disposeList = new List <Action>();

            CXUnsavedFile cxUnsaved    = default;
            uint          unsavedFiles = default;

            if (string.IsNullOrEmpty(unsaved))
            {
                unsavedFiles = 0;
            }
            else
            {
                // use unsaved files
                unsavedFiles = 1;
                var contentsBytes  = Encoding.UTF8.GetBytes(unsaved);
                var contentsHandle = GCHandle.Alloc(contentsBytes, GCHandleType.Pinned);
                disposeList.Add(() => contentsHandle.Free());
                var filenameHandle = GCHandle.Alloc(filenameBytes, GCHandleType.Pinned);
                disposeList.Add(() => filenameHandle.Free());
                cxUnsaved = new CXUnsavedFile
                {
                    Filename = filenameHandle.AddrOfPinnedObject(),
                    Contents = contentsHandle.AddrOfPinnedObject(),
                    Length   = (uint)contentsBytes.Length,
                };
            }

            // CXUnsavedFileをエントリポイントとしてパースする
            var tu = libclang.clang_parseTranslationUnit(index,
                                                         ref filenameBytes[0],
                                                         ref ptrs[0], ptrs.Length,
                                                         ref cxUnsaved, unsavedFiles,
                                                         options);

            foreach (var x in disposeList)
            {
                x();
            }
            foreach (var buffer in buffers)
            {
                buffer.Dispose();
            }

            if (tu == IntPtr.Zero)
            {
                return(null);
            }
            return(new ClangTU(index, tu));
        }