Beispiel #1
0
        private static string GetTripleFromOptions(CppParserOptions options)
        {
            // From https://clang.llvm.org/docs/CrossCompilation.html
            // <arch><sub>-<vendor>-<sys>-<abi>
            var targetCpu    = GetTargetCpuAsString(options.TargetCpu);
            var targetCpuSub = options.TargetCpuSub ?? string.Empty;
            var targetVendor = options.TargetVendor ?? "pc";
            var targetSystem = options.TargetSystem ?? "windows";
            var targetAbi    = options.TargetAbi ?? "";

            return($"{targetCpu}{targetCpuSub}-{targetVendor}-{targetSystem}-{targetAbi}");
        }
Beispiel #2
0
        /// <summary>
        /// Parse the specified single file.
        /// </summary>
        /// <param name="cppFilename">A path to a C/C++ file on the disk to parse</param>
        /// <param name="options">Options used for parsing this file (e.g include folders...)</param>
        /// <returns>The result of the compilation</returns>
        public static CppCompilation ParseFile(string cppFilename, CppParserOptions options = null)
        {
            if (cppFilename == null)
            {
                throw new ArgumentNullException(nameof(cppFilename));
            }
            var files = new List <string> {
                cppFilename
            };

            return(ParseFiles(files, options));
        }
Beispiel #3
0
        /// <summary>
        /// Parse the specified C++ text in-memory.
        /// </summary>
        /// <param name="cppText">A string with a C/C++ text</param>
        /// <param name="options">Options used for parsing this file (e.g include folders...)</param>
        /// <param name="cppFilename">Optional path to a file only used for reporting errors. Default is 'content'</param>
        /// <returns>The result of the compilation</returns>
        public static CppCompilation Parse(string cppText, CppParserOptions options = null, string cppFilename = "content")
        {
            if (cppText == null)
            {
                throw new ArgumentNullException(nameof(cppText));
            }
            var cppFiles = new List <CppFileOrString> {
                new CppFileOrString {
                    Filename = cppFilename, Content = cppText
                }
            };

            return(ParseInternal(cppFiles, options));
        }
Beispiel #4
0
        /// <summary>
        /// Parse the specified single file.
        /// </summary>
        /// <param name="cppFilenameList">A list of path to C/C++ header files on the disk to parse</param>
        /// <param name="options">Options used for parsing this file (e.g include folders...)</param>
        /// <returns>The result of the compilation</returns>
        public static CppCompilation ParseFiles(List <string> cppFilenameList, CppParserOptions options = null)
        {
            if (cppFilenameList == null)
            {
                throw new ArgumentNullException(nameof(cppFilenameList));
            }

            var cppFiles = new List <CppFileOrString>();

            foreach (var cppFilepath in cppFilenameList)
            {
                if (string.IsNullOrEmpty(cppFilepath))
                {
                    throw new InvalidOperationException("A null or empty filename is invalid in the list");
                }
                cppFiles.Add(new CppFileOrString {
                    Filename = cppFilepath
                });
            }
            return(ParseInternal(cppFiles, options));
        }
Beispiel #5
0
        /// <summary>
        /// Private method parsing file or content.
        /// </summary>
        /// <param name="cppFiles">A list of path to C/C++ header files on the disk to parse</param>
        /// <param name="options">Options used for parsing this file (e.g include folders...)</param>
        /// <returns>The result of the compilation</returns>
        private static CppCompilation ParseInternal(List <CppFileOrString> cppFiles, CppParserOptions options = null)
        {
            if (cppFiles == null)
            {
                throw new ArgumentNullException(nameof(cppFiles));
            }

            options = options ?? new CppParserOptions();

            var arguments = new List <string>();

            // Make sure that paths are absolute
            var normalizedIncludePaths = new List <string>();

            normalizedIncludePaths.AddRange(options.IncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            var normalizedSystemIncludePaths = new List <string>();

            normalizedSystemIncludePaths.AddRange(options.SystemIncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            arguments.AddRange(options.AdditionalArguments);
            arguments.AddRange(normalizedIncludePaths.Select(x => $"-I{x}"));
            arguments.AddRange(normalizedSystemIncludePaths.Select(x => $"-isystem{x}"));
            arguments.AddRange(options.Defines.Select(x => $"-D{x}"));

            if (options.ParseAsCpp && !arguments.Contains("-xc++"))
            {
                arguments.Add("-xc++");
            }

            if (!arguments.Any(x => x.StartsWith("--target=")))
            {
                arguments.Add($"--target={GetTripleFromOptions(options)}");
            }

            if (options.ParseComments)
            {
                arguments.Add("-fparse-all-comments");
            }

            var translationFlags = CXTranslationUnit_Flags.CXTranslationUnit_None;

            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;                   // Don't traverse function bodies
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes;               // Include attributed types in CXType
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes;              // Implicit attributes should be visited

            if (options.ParseMacros)
            {
                translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;
            }

            var argumentsArray = arguments.ToArray();

            using (var createIndex = CXIndex.Create())
            {
                var builder = new CppModelBuilder {
                    AutoSquashTypedef = options.AutoSquashTypedef
                };
                var compilation = builder.RootCompilation;

                string rootFileName    = CppAstRootFileName;
                string rootFileContent = null;

                // Build the root input source file
                var tempBuilder = new StringBuilder();
                if (options.PreHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PreHeaderText);
                }

                foreach (var file in cppFiles)
                {
                    if (file.Content != null)
                    {
                        tempBuilder.AppendLine(file.Content);
                    }
                    else
                    {
                        var filePath = Path.Combine(Environment.CurrentDirectory, file.Filename);
                        tempBuilder.AppendLine($"#include \"{filePath}\"");
                    }
                }

                if (options.PostHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PostHeaderText);
                }

                // TODO: Add debug
                rootFileContent = tempBuilder.ToString();

                compilation.InputText = rootFileContent;

                {
                    CXTranslationUnit translationUnit;
                    CXErrorCode       translationUnitError;

                    translationUnitError = CXTranslationUnit.Parse(createIndex, rootFileName, argumentsArray, new CXUnsavedFile[] { new CXUnsavedFile()
                                                                                                                                    {
                                                                                                                                        Contents = rootFileContent,
                                                                                                                                        Filename = rootFileName,
                                                                                                                                        Length   = (uint)Encoding.UTF8.GetByteCount(rootFileContent)
                                                                                                                                    } }, translationFlags, out translationUnit);

                    bool skipProcessing = false;

                    if (translationUnitError != CXErrorCode.CXError_Success)
                    {
                        compilation.Diagnostics.Error($"Parsing failed due to '{translationUnitError}'", new CppSourceLocation(rootFileName, 0, 1, 1));
                        skipProcessing = true;
                    }
                    else if (translationUnit.NumDiagnostics != 0)
                    {
                        for (uint i = 0; i < translationUnit.NumDiagnostics; ++i)
                        {
                            using (var diagnostic = translationUnit.GetDiagnostic(i))
                            {
                                CppSourceLocation location;
                                var message = GetMessageAndLocation(rootFileContent, diagnostic, out location);

                                switch (diagnostic.Severity)
                                {
                                case CXDiagnosticSeverity.CXDiagnostic_Ignored:
                                case CXDiagnosticSeverity.CXDiagnostic_Note:
                                    compilation.Diagnostics.Info(message, location);
                                    break;

                                case CXDiagnosticSeverity.CXDiagnostic_Warning:
                                    compilation.Diagnostics.Warning(message, location);
                                    break;

                                case CXDiagnosticSeverity.CXDiagnostic_Error:
                                case CXDiagnosticSeverity.CXDiagnostic_Fatal:
                                    compilation.Diagnostics.Error(message, location);
                                    skipProcessing = true;
                                    break;
                                }
                            }
                        }
                    }

                    if (skipProcessing)
                    {
                        compilation.Diagnostics.Warning($"Compilation aborted due to one or more errors listed above.", new CppSourceLocation(rootFileName, 0, 1, 1));
                    }
                    else
                    {
                        using (translationUnit)
                        {
                            translationUnit.Cursor.VisitChildren(builder.VisitTranslationUnit, clientData: default);
                        }
                    }
                }

                return(compilation);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Private method parsing file or content.
        /// </summary>
        /// <param name="cppFiles">A list of path to C/C++ header files on the disk to parse</param>
        /// <param name="options">Options used for parsing this file (e.g include folders...)</param>
        /// <returns>The result of the compilation</returns>
        private static unsafe CppCompilation ParseInternal(List <CppFileOrString> cppFiles, CppParserOptions options = null)
        {
            if (cppFiles == null)
            {
                throw new ArgumentNullException(nameof(cppFiles));
            }

            options = options ?? new CppParserOptions();

            var arguments = new List <string>();

            // Make sure that paths are absolute
            var normalizedIncludePaths = new List <string>();

            normalizedIncludePaths.AddRange(options.IncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            var normalizedSystemIncludePaths = new List <string>();

            normalizedSystemIncludePaths.AddRange(options.SystemIncludeFolders.Select(x => Path.Combine(Environment.CurrentDirectory, x)));

            arguments.AddRange(options.AdditionalArguments);
            arguments.AddRange(normalizedIncludePaths.Select(x => $"-I{x}"));
            arguments.AddRange(normalizedSystemIncludePaths.Select(x => $"-isystem{x}"));
            arguments.AddRange(options.Defines.Select(x => $"-D{x}"));

            arguments.Add("-dM");
            arguments.Add("-E");

            if (options.ParseAsCpp && !arguments.Contains("-xc++"))
            {
                arguments.Add("-xc++");
            }

            if (!arguments.Any(x => x.StartsWith("--target=")))
            {
                arguments.Add($"--target={GetTripleFromOptions(options)}");
            }

            if (options.ParseComments)
            {
                arguments.Add("-fparse-all-comments");
            }

            var translationFlags = CXTranslationUnit_Flags.CXTranslationUnit_None;

            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies;                   // Don't traverse function bodies
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes;               // Include attributed types in CXType
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes;              // Implicit attributes should be visited

            if (options.ParseMacros)
            {
                translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;
            }
            translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_DetailedPreprocessingRecord;

            var argumentsArray = arguments.ToArray();

            using (var createIndex = CXIndex.Create())
            {
                var builder = new CppModelBuilder
                {
                    AutoSquashTypedef     = options.AutoSquashTypedef,
                    ParseSystemIncludes   = options.ParseSystemIncludes,
                    ParseAttributeEnabled = options.ParseAttributes,
                };
                var compilation = builder.RootCompilation;

                string rootFileName    = CppAstRootFileName;
                string rootFileContent = null;

                // Creates a fake 'header.hpp' that includes all the files we passed, so they are parsed all at once

                // Build the root input source file
                var tempBuilder = new StringBuilder();
                if (options.PreHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PreHeaderText);
                }

                foreach (var file in cppFiles)
                {
                    if (file.Content != null)
                    {
                        tempBuilder.AppendLine(file.Content);
                    }
                    else
                    {
                        var filePath = Path.Combine(Environment.CurrentDirectory, file.Filename);
                        tempBuilder.AppendLine($"#include \"{filePath}\"");
                    }
                }

                if (options.PostHeaderText != null)
                {
                    tempBuilder.AppendLine(options.PostHeaderText);
                }

                // TODO: Add debug
                rootFileContent = tempBuilder.ToString();

                var rootFileContentUTF8 = Encoding.UTF8.GetBytes(rootFileContent);
                compilation.InputText = rootFileContent;

                fixed(void *rootFileContentUTF8Ptr = rootFileContentUTF8)
                {
                    CXTranslationUnit translationUnit;

                    var rootFileNameUTF8 = Marshal.StringToHGlobalAnsi(rootFileName);

                    translationUnit = CXTranslationUnit.Parse(createIndex, rootFileName, argumentsArray, new CXUnsavedFile[]
                    {
                        new CXUnsavedFile()
                        {
                            Contents = (sbyte *)rootFileContentUTF8Ptr,
                            Filename = (sbyte *)rootFileNameUTF8,
                            Length   = new UIntPtr((uint)rootFileContentUTF8.Length)
                        }
                    }, translationFlags);

                    // Skips the processing of the file if 1 error is raised
                    // We don't want that, so remove that part

                    //bool skipProcessing = false;

                    //if (translationUnit.NumDiagnostics != 0)
                    //{
                    //    for (uint i = 0; i < translationUnit.NumDiagnostics; ++i)
                    //    {
                    //        using (var diagnostic = translationUnit.GetDiagnostic(i))
                    //        {
                    //            var message = GetMessageAndLocation(rootFileContent, diagnostic, out var location);

                    //            switch (diagnostic.Severity)
                    //            {
                    //                case CXDiagnosticSeverity.CXDiagnostic_Ignored:
                    //                case CXDiagnosticSeverity.CXDiagnostic_Note:
                    //                    compilation.Diagnostics.Info(message, location);
                    //                    break;
                    //                case CXDiagnosticSeverity.CXDiagnostic_Warning:
                    //                    compilation.Diagnostics.Warning(message, location);
                    //                    break;
                    //                case CXDiagnosticSeverity.CXDiagnostic_Error:
                    //                case CXDiagnosticSeverity.CXDiagnostic_Fatal:
                    //                    compilation.Diagnostics.Error(message, location);
                    //                    skipProcessing = true;
                    //                    break;
                    //            }
                    //        }
                    //    }
                    //}

                    //if (skipProcessing)
                    //{
                    //    compilation.Diagnostics.Warning($"Compilation aborted due to one or more errors listed above.", new CppSourceLocation(rootFileName, 0, 1, 1));
                    //}
                    //else
                    //{
                    using (translationUnit)
                    {
                        translationUnit.Cursor.VisitChildren(builder.VisitTranslationUnit, clientData: default);
                    }
                    //}
                }

                return(compilation);
            }
        }