Beispiel #1
0
        private static string GetMessageAndLocation(string rootContent, CXDiagnostic diagnostic, out CppSourceLocation location)
        {
            var builder = new StringBuilder();

            builder.Append(diagnostic.ToString());
            location = CppModelBuilder.GetSourceLocation(diagnostic.Location);
            if (location.File == CppAstRootFileName)
            {
                var    reader = new StringReader(rootContent);
                var    lines  = new List <string>();
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    lines.Add(line);
                }

                var lineIndex = location.Line - 1;
                if (lineIndex < lines.Count)
                {
                    builder.AppendLine();
                    builder.AppendLine(lines[lineIndex]);
                    for (int i = 0; i < location.Column - 1; i++)
                    {
                        builder.Append(i + 1 == location.Column - 1 ? "-" : " ");
                    }

                    builder.AppendLine("^-");
                }
            }

            return(builder.ToString());
        }
Beispiel #2
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 #3
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);
            }
        }