private ClangTranslationUnit GenerateTranslationUnit(ISourceFile file, List<ClangUnsavedFile> unsavedFiles)
{
ClangTranslationUnit result = null;
if (System.IO.File.Exists(file.Location))
{
var args = new List<string>();
var superProject = file.Project.Solution.StartupProject as IStandardProject;
var project = file.Project as IStandardProject;
var toolchainIncludes = superProject.ToolChain?.GetToolchainIncludes(file);
if (toolchainIncludes != null)
{
foreach (var include in toolchainIncludes)
{
AddArgument(args, string.Format("-isystem{0}", include));
}
}
// toolchain includes
// This code is same as in toolchain, get compiler arguments... does this need a refactor, or toolchain get passed in? Clang take GCC compatible arguments.
// perhaps this language service has its own clang tool chain, to generate compiler arguments from project configuration?
// Referenced includes
var referencedIncludes = project.GetReferencedIncludes();
foreach (var include in referencedIncludes)
{
AddArgument(args, string.Format("-I{0}", include));
}
// global includes
var globalIncludes = superProject.GetGlobalIncludes();
foreach (var include in globalIncludes)
{
AddArgument(args, string.Format("-I{0}", include));
}
// public includes
foreach (var include in project.PublicIncludes)
{
AddArgument(args, string.Format("-I{0}", include));
}
// includes
foreach (var include in project.Includes)
{
AddArgument(args, string.Format("-I{0}", Path.Combine(project.CurrentDirectory, include.Value)));
}
var referencedDefines = project.GetReferencedDefines();
foreach (var define in referencedDefines)
{
AddArgument(args, string.Format("-D{0}", define));
}
// global includes
var globalDefines = superProject.GetGlobalDefines();
foreach (var define in globalDefines)
{
AddArgument(args, string.Format("-D{0}", define));
}
foreach (var define in project.Defines)
{
AddArgument(args, string.Format("-D{0}", define));
}
//foreach (var arg in superProject.ToolChainArguments)
//{
// args.Add(string.Format("{0}", arg));
//}
//foreach (var arg in superProject.CompilerArguments)
//{
// args.Add(string.Format("{0}", arg));
//}
switch (file.Extension)
{
case ".c":
{
foreach (var arg in superProject.CCompilerArguments)
{
args.Add(string.Format("{0}", arg));
}
}
break;
case ".cpp":
{
foreach (var arg in superProject.CppCompilerArguments)
{
args.Add(string.Format("{0}", arg));
}
}
break;
}
// TODO do we mark files as class header? CAn clang auto detect this?
//if (file.Language == Language.Cpp)
{
args.Add("-xc++");
args.Add("-std=c++14");
args.Add("-D__STDC__"); // This is needed to ensure inbuilt functions are appropriately prototyped.
}
args.Add("-Wunused-variable");
result = index.ParseTranslationUnit(file.Location, args.ToArray(), unsavedFiles.ToArray(),
TranslationUnitFlags.IncludeBriefCommentsInCodeCompletion | TranslationUnitFlags.PrecompiledPreamble |
TranslationUnitFlags.CacheCompletionResults | TranslationUnitFlags.Incomplete);
}
if (result == null)
{
throw new Exception("Error generating translation unit.");
}
return result;
}