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)); }
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); }
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); }
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 } } }; }
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); }
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); }
/// <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)); }
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); } }
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)); }