Exemplo n.º 1
0
        /// <summary>
        /// Get the parameters to a specified function defined in a file in the include
        /// cache.
        /// </summary>
        /// <param name="function">
        /// The name of the function for which to find parameters.
        /// </param>
        /// <returns>
        /// A list of the function's parameters or null if the function could not be
        /// found.
        /// </returns>
        public List <string> GetParametersFromIncludeCache(string function)
        {
            string fileName = null;
            IEnumerable <IncludeCacheEntry> entries = _includeCache.Values.Where(
                x => x.Functions.Any(y => y.Equals(function,
                                                   StringComparison.CurrentCultureIgnoreCase)) ||
                x.Macros.Any(y => y.Equals(function,
                                           StringComparison.CurrentCultureIgnoreCase)));

            foreach (IncludeCacheEntry entry in entries)
            {
                fileName = entry.FileName;
                break;
            }
            if (fileName != null)
            {
                try
                {
                    string[] includeLines = File.ReadAllLines(fileName);
                    return(CMakeParsing.ParseForParameterNames(includeLines, function));
                }
                catch (IOException)
                {
                    // Just ignore any errors.
                }
            }
            return(null);
        }
Exemplo n.º 2
0
        private void UpdateIncludeCacheItem(string include)
        {
            string curFileDir = Path.GetDirectoryName(GetFilePath());
            string path       = null;
            bool   needUpdate = true;

            if (_includeCache.ContainsKey(include) &&
                File.Exists(_includeCache[include].FileName))
            {
                path       = _includeCache[include].FileName;
                needUpdate =
                    (File.GetLastWriteTime(path) != _includeCache[include].TimeStamp);
            }
            else
            {
                path = Path.Combine(curFileDir, include + ".cmake");
                if (!File.Exists(path))
                {
                    path = Path.Combine(CMakePath.FindCMakeModules(),
                                        include + ".cmake");
                    if (!File.Exists(path))
                    {
                        path = null;
                    }
                }
            }
            if (path != null && needUpdate)
            {
                try
                {
                    string[] includeLines = File.ReadAllLines(path);
                    bool     rootRef      = _includeCache.ContainsKey(include) &&
                                            _includeCache[include].RootRef;
                    _includeCache[include] = new IncludeCacheEntry()
                    {
                        FileName     = path,
                        TimeStamp    = File.GetLastWriteTime(path),
                        RootRef      = rootRef,
                        Variables    = CMakeParsing.ParseForVariables(includeLines),
                        EnvVariables = CMakeParsing.ParseForEnvVariables(
                            includeLines),
                        CacheVariables = CMakeParsing.ParseForCacheVariables(
                            includeLines),
                        Functions = CMakeParsing.ParseForFunctionNames(includeLines,
                                                                       false),
                        Macros = CMakeParsing.ParseForFunctionNames(includeLines,
                                                                    true),
                        Dependencies = CMakeParsing.ParseForIncludes(includeLines)
                    };
                    foreach (string dependency in _includeCache[include].Dependencies)
                    {
                        UpdateIncludeCacheItem(dependency);
                    }
                }
                catch (IOException)
                {
                    // Just ignore any errors.
                }
            }
        }
Exemplo n.º 3
0
        private static CMakeItemDeclarations CreateCacheVariableDeclarations(
            CMakeCommandId id, ParseRequest req, Source source,
            List <string> priorParameters)
        {
            List <string> vars = CMakeParsing.ParseForCacheVariables(source.GetLines());

            return(new CMakeVariableDeclarations(vars, CMakeVariableType.CacheVariable));
        }
Exemplo n.º 4
0
        private static CMakeItemDeclarations CreateTargetDeclarations(CMakeCommandId id,
                                                                      ParseRequest req, Source source, List <string> priorParameters)
        {
            List <string>         targets = CMakeParsing.ParseForTargetNames(source.GetLines());
            CMakeItemDeclarations decls   = new CMakeItemDeclarations();

            decls.AddItems(targets, CMakeItemDeclarations.ItemType.Target);
            decls.ExcludeItems(priorParameters);
            return(decls);
        }
Exemplo n.º 5
0
        private static CMakeItemDeclarations CreateInstalledFileDeclarations(
            CMakeCommandId id, ParseRequest req, Source source,
            List <string> priorParameters)
        {
            List <string> installedFiles = CMakeParsing.ParseForInstalledFiles(
                source.GetLines());
            CMakeItemDeclarations decls = new CMakeItemDeclarations();

            decls.AddItems(installedFiles, CMakeItemDeclarations.ItemType.SourceFile);
            decls.ExcludeItems(priorParameters);
            return(decls);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Update the include cache with information on the files referenced by the
        /// specified lines.
        /// </summary>
        /// <param name="lines">A collection of lines.</param>
        public void BuildIncludeCache(IEnumerable <string> lines)
        {
            foreach (IncludeCacheEntry entry in _includeCache.Values)
            {
                entry.RootRef = false;
            }
            List <string> includes = CMakeParsing.ParseForIncludes(lines);

            foreach (string include in includes)
            {
                UpdateIncludeCacheItem(include);
                if (_includeCache.ContainsKey(include))
                {
                    _includeCache[include].RootRef = true;
                }
            }
        }
Exemplo n.º 7
0
 public override int FormatSpan(IVsTextLines buffer, TextSpan[] ts)
 {
     foreach (TextSpan span in ts)
     {
         // Set the indentation of each line in the snippet to match the first
         // line.
         LanguagePreferences prefs = Source.LanguageService.Preferences;
         char indentChar           = prefs.InsertTabs ? '\t' : ' ';
         int  level = CMakeParsing.GetIndentationLevel(
             Source.GetLine(span.iStartLine), indentChar);
         for (int i = span.iStartLine + 1; i <= span.iEndLine; ++i)
         {
             Source.SetText(i, 0, i, 0, new string(indentChar, level));
         }
     }
     return(VSConstants.S_OK);
 }
Exemplo n.º 8
0
        public override bool HandleSmartIndent()
        {
            // If the line contains an outer opening parenthesis, intent by one level.
            // If the line contains an outer closing parenthesis, unindent to match the
            // level of the corresponding opening parenthesis.  In all other cases,
            // match the indentation level of the previous line.
            LanguagePreferences prefs = Source.LanguageService.Preferences;
            char indentChar           = prefs.InsertTabs ? '\t' : ' ';
            int  line;
            int  col;

            TextView.GetCaretPos(out line, out col);
            List <string> lines    = Source.GetLines().ToList();
            int           prevLine = CMakeParsing.GetLastNonEmptyLine(lines, line - 1);
            int           level    = CMakeParsing.GetIndentationLevel(lines[prevLine], indentChar);
            int           lineToMatch;

            if (CMakeParsing.ShouldIndent(lines, prevLine))
            {
                level += prefs.InsertTabs ? 1 : prefs.IndentSize;
            }
            else if (CMakeParsing.ShouldUnindent(lines, prevLine, out lineToMatch))
            {
                if (lineToMatch < 0)
                {
                    level = 0;
                }
                else
                {
                    level = CMakeParsing.GetIndentationLevel(lines[lineToMatch], indentChar);
                }
            }
            int oldIndentLen = 0;

            while (oldIndentLen < lines[line].Length &&
                   lines[line][oldIndentLen] == indentChar)
            {
                oldIndentLen++;
            }
            Source.SetText(line, 0, line, oldIndentLen, new string(indentChar, level));
            TextView.PositionCaretForEditing(line, level);
            return(true);
        }
Exemplo n.º 9
0
 public override string GetDataTipText(int line, int col, out TextSpan span)
 {
     CMakeParsing.TokenData tokenData;
     if (_lines != null &&
         CMakeParsing.ParseForToken(_lines, line, col, out tokenData) &&
         !tokenData.InParens)
     {
         if (tokenData.TokenInfo.Token == (int)CMakeToken.Keyword)
         {
             // Get a Quick Info tip for the command at the cursor.
             span = tokenData.TokenInfo.ToTextSpan(line);
             string         lineText  = _lines.ToList()[line];
             string         tokenText = lineText.ExtractToken(tokenData.TokenInfo);
             CMakeCommandId id        = CMakeKeywords.GetCommandId(tokenText);
             if (CMakeSubcommandMethods.HasSubcommands(id))
             {
                 // Parse to get the subcommand, if there is one.
                 CMakeParsing.ParameterInfoResult result =
                     CMakeParsing.ParseForParameterInfo(_lines, line, -1, true);
                 return(CMakeSubcommandMethods.GetSubcommandQuickInfoTip(id,
                                                                         result.SubcommandName));
             }
             return(CMakeMethods.GetCommandQuickInfoTip(id));
         }
         else if (tokenData.TokenInfo.Token == (int)CMakeToken.Identifier)
         {
             // Get a Quick Info tip for the function called at the cursor, if
             // there is one.
             string        lineText   = _lines.ToList()[line];
             string        tokenText  = lineText.ExtractToken(tokenData.TokenInfo);
             List <string> parameters = CMakeParsing.ParseForParameterNames(_lines,
                                                                            tokenText);
             if (parameters != null)
             {
                 span = tokenData.TokenInfo.ToTextSpan(line);
                 return(string.Format("{0}({1})", tokenText,
                                      string.Join(" ", parameters)));
             }
         }
     }
     span = new TextSpan();
     return(null);
 }
Exemplo n.º 10
0
 public override string Goto(VSConstants.VSStd97CmdID cmd, IVsTextView textView,
                             int line, int col, out TextSpan span)
 {
     if (_lines != null && (cmd == VSConstants.VSStd97CmdID.GotoDefn ||
                            cmd == VSConstants.VSStd97CmdID.GotoDecl))
     {
         // Parse for any identifier that may be at the cursor.  If the is one,
         // find the variable or function definition for that identifier and jump
         // to it.
         bool   isVariable = false;
         string identifier = CMakeParsing.ParseForIdentifier(_lines, line, col,
                                                             out isVariable);
         if (identifier != null)
         {
             if (isVariable)
             {
                 if (CMakeParsing.ParseForVariableDefinition(_lines, identifier,
                                                             out span))
                 {
                     span.iEndIndex++;
                     return(_fileName);
                 }
             }
             else
             {
                 if (CMakeParsing.ParseForFunctionDefinition(_lines, identifier,
                                                             out span))
                 {
                     span.iEndIndex++;
                     return(_fileName);
                 }
             }
         }
     }
     span = new TextSpan();
     return(null);
 }
Exemplo n.º 11
0
        public override AuthoringScope ParseSource(ParseRequest req)
        {
            CMakeAuthoringScope scope = new CMakeAuthoringScope();

            if (!CMakeSource.IsCMakeFile(req.FileName))
            {
                // Don't do IntelliSense parsing for ordinary text files.
                return(scope);
            }
            CMakeSource source = (CMakeSource)GetSource(req.FileName);

            if (req.Sink.HiddenRegions)
            {
                req.Sink.ProcessHiddenRegions = true;
                List <TextSpan> regions = CMakeParsing.ParseForFunctionBodies(
                    source.GetLines());
                foreach (TextSpan textSpan in regions)
                {
                    req.Sink.AddHiddenRegion(textSpan);
                }
            }
            if (req.Sink.BraceMatching)
            {
                List <CMakeParsing.SpanPair> pairs = null;
                switch ((CMakeToken)req.TokenInfo.Token)
                {
                case CMakeToken.OpenParen:
                case CMakeToken.CloseParen:
                    pairs = CMakeParsing.ParseForParens(source.GetLines());
                    break;

                case CMakeToken.VariableStart:
                case CMakeToken.VariableStartEnv:
                case CMakeToken.VariableStartCache:
                case CMakeToken.VariableStartSetEnv:
                case CMakeToken.VariableEnd:
                    pairs = CMakeParsing.ParseForVariableBraces(source.GetLines(),
                                                                req.Line);
                    break;

                case CMakeToken.GeneratorStart:
                case CMakeToken.GeneratorEnd:
                    pairs = CMakeParsing.ParseForGeneratorBraces(source.GetLines(),
                                                                 req.Line);
                    break;
                }
                if (pairs != null)
                {
                    foreach (CMakeParsing.SpanPair pair in pairs)
                    {
                        req.Sink.MatchPair(pair.First, pair.Second, 0);
                    }
                }
            }
            if (req.Reason == ParseReason.MemberSelect ||
                req.Reason == ParseReason.MemberSelectAndHighlightBraces ||
                req.Reason == ParseReason.CompleteWord)
            {
                // Set an appropriate declarations object depending on the token that
                // triggered member selection.
                CMakeToken token = (CMakeToken)req.TokenInfo.Token;
                if (token == CMakeToken.String)
                {
                    // If the token is a string and the user has began to reference a
                    // variable inside the string, treat the string as if it was the
                    // appropriate type of variable start token and display member
                    // selection for variables.
                    string line      = source.GetLine(req.Line);
                    string tokenText = line.ExtractToken(req.TokenInfo);
                    if (tokenText.EndsWith("${"))
                    {
                        token = CMakeToken.VariableStart;
                    }
                    else if (tokenText.EndsWith("$ENV{"))
                    {
                        token = CMakeToken.VariableStartEnv;
                    }
                    else if (tokenText.EndsWith("$CACHE{"))
                    {
                        token = CMakeToken.VariableStartCache;
                    }
                }
                if (token == CMakeToken.VariableStart)
                {
                    List <string> vars = CMakeParsing.ParseForVariables(
                        source.GetLines(), req.Line);
                    CMakeVariableDeclarations decls = new CMakeVariableDeclarations(vars,
                                                                                    CMakeVariableType.Variable);
                    decls.AddItems(source.GetIncludeCacheVariables(),
                                   CMakeItemDeclarations.ItemType.Variable);
                    string functionName = CMakeParsing.ParseForCurrentFunction(
                        source.GetLines(), req.Line);
                    if (functionName != null)
                    {
                        List <string> paramNames = CMakeParsing.ParseForParameterNames(
                            source.GetLines(), functionName);
                        paramNames.Add("ARGN");
                        decls.AddItems(paramNames,
                                       CMakeItemDeclarations.ItemType.Variable);
                    }
                    scope.SetDeclarations(decls);
                }
                else if (token == CMakeToken.VariableStartEnv)
                {
                    List <string> vars = CMakeParsing.ParseForEnvVariables(
                        source.GetLines());
                    CMakeVariableDeclarations decls = new CMakeVariableDeclarations(vars,
                                                                                    CMakeVariableType.EnvVariable);
                    decls.AddItems(source.GetIncludeCacheEnvVariables(),
                                   CMakeItemDeclarations.ItemType.Variable);
                    scope.SetDeclarations(decls);
                }
                else if (token == CMakeToken.VariableStartCache)
                {
                    List <string> vars = CMakeParsing.ParseForCacheVariables(
                        source.GetLines());
                    CMakeVariableDeclarations decls = new CMakeVariableDeclarations(vars,
                                                                                    CMakeVariableType.CacheVariable);
                    decls.AddItems(source.GetIncludeCacheCacheVariables(),
                                   CMakeItemDeclarations.ItemType.Variable);
                    scope.SetDeclarations(decls);
                }
                else if (token == CMakeToken.Identifier)
                {
                    CMakeParsing.TokenData tokenData;
                    CMakeParsing.ParseForToken(source.GetLines(), req.Line,
                                               req.TokenInfo.StartIndex, out tokenData);
                    if (!tokenData.InParens)
                    {
                        CMakeItemDeclarations decls    = new CMakeItemDeclarations();
                        IEnumerable <string>  commands = CMakeKeywords.GetAllCommands(
                            CMakePackage.Instance.CMakeOptionPage.ShowDeprecated);
                        if (!CMakePackage.Instance.CMakeOptionPage.CommandsLower)
                        {
                            commands = commands.Select(x => x.ToUpper());
                        }
                        decls.AddItems(commands, CMakeItemDeclarations.ItemType.Command);
                        decls.AddItems(
                            CMakeParsing.ParseForFunctionNames(source.GetLines(), false),
                            CMakeItemDeclarations.ItemType.Function);
                        decls.AddItems(
                            CMakeParsing.ParseForFunctionNames(source.GetLines(), true),
                            CMakeItemDeclarations.ItemType.Macro);
                        decls.AddItems(source.GetIncludeCacheFunctions(),
                                       CMakeItemDeclarations.ItemType.Function);
                        decls.AddItems(source.GetIncludeCacheMacros(),
                                       CMakeItemDeclarations.ItemType.Macro);
                        scope.SetDeclarations(decls);
                    }
                    else
                    {
                        Declarations decls = CMakeDeclarationsFactory.CreateDeclarations(
                            tokenData.Command, req, source,
                            tokenData.ParameterIndex > 0 ? tokenData.PriorParameters : null);
                        scope.SetDeclarations(decls);
                    }
                }
                else if (token == CMakeToken.OpenParen)
                {
                    CMakeCommandId id = CMakeParsing.ParseForTriggerCommandId(
                        source.GetLines(), req.Line, req.TokenInfo.StartIndex);
                    Declarations decls = CMakeDeclarationsFactory.CreateDeclarations(
                        id, req, source);
                    scope.SetDeclarations(decls);
                }
                else if (token == CMakeToken.WhiteSpace)
                {
                    CMakeParsing.TokenData tokenData;
                    CMakeParsing.ParseForToken(source.GetLines(), req.Line,
                                               req.TokenInfo.StartIndex, out tokenData);
                    Declarations decls = CMakeDeclarationsFactory.CreateDeclarations(
                        tokenData.Command, req, source,
                        tokenData.ParameterIndex > 0 ? tokenData.PriorParameters : null);
                    scope.SetDeclarations(decls);
                }
                else if (token == CMakeToken.GeneratorStart)
                {
                    scope.SetDeclarations(new CMakeGeneratorDeclarations());
                }
            }
            else if (req.Reason == ParseReason.MethodTip)
            {
                CMakeParsing.ParameterInfoResult result =
                    CMakeParsing.ParseForParameterInfo(source.GetLines(), req.Line,
                                                       req.TokenInfo.EndIndex);
                if (result.CommandName != null && result.CommandSpan.HasValue)
                {
                    if (result.SubcommandName == null)
                    {
                        req.Sink.StartName(result.CommandSpan.Value, result.CommandName);
                    }
                    else
                    {
                        req.Sink.StartName(result.CommandSpan.Value,
                                           result.CommandSpan + "(" + result.SubcommandName);
                    }
                    if (result.BeginSpan.HasValue)
                    {
                        req.Sink.StartParameters(result.BeginSpan.Value);
                    }
                    foreach (TextSpan span in result.SeparatorSpans)
                    {
                        req.Sink.NextParameter(span);
                    }
                    if (result.EndSpan.HasValue)
                    {
                        req.Sink.EndParameters(result.EndSpan.Value);
                    }
                    CMakeCommandId id = CMakeKeywords.GetCommandId(result.CommandName);
                    if (id == CMakeCommandId.Unspecified)
                    {
                        // If it's a user-defined function or macro, parse to try to find
                        // its parameters.
                        List <string> parameters = CMakeParsing.ParseForParameterNames(
                            source.GetLines(), result.CommandName);
                        if (parameters == null)
                        {
                            parameters = source.GetParametersFromIncludeCache(
                                result.CommandName);
                        }
                        if (parameters != null)
                        {
                            scope.SetMethods(new CMakeUserMethods(result.CommandName,
                                                                  parameters));
                        }
                    }
                    else
                    {
                        scope.SetMethods(CMakeMethods.GetCommandParameters(id,
                                                                           result.SubcommandName));
                    }
                }
            }
            else if (req.Reason == ParseReason.Goto)
            {
                scope.SetLines(source.GetLines());
                scope.SetFileName(req.FileName);
            }
            else if (req.Reason == ParseReason.QuickInfo)
            {
                scope.SetLines(source.GetLines());
            }
            else if (req.Reason == ParseReason.Check)
            {
                foreach (ParseForErrorMethod method in _parseForErrorMethods)
                {
                    List <CMakeErrorInfo> info = method(source.GetLines());
                    foreach (CMakeErrorInfo item in info)
                    {
                        CMakeError err = item.ErrorCode;
                        if (_errorStrings.ContainsKey(err) &&
                            (!_enabledMethods.ContainsKey(err) || _enabledMethods[err]()))
                        {
                            req.Sink.AddError(req.FileName, _errorStrings[err], item.Span,
                                              item.Warning ? Severity.Warning : Severity.Error);
                        }
                    }
                }
                if (CMakePackage.Instance.CMakeOptionPage.ParseIncludedFiles)
                {
                    source.BuildIncludeCache(source.GetLines());
                    source.UpdateIncludeCache();
                    source.PruneIncludeCache();
                }
                else
                {
                    source.ClearIncludeCache();
                }
            }
            return(scope);
        }
Exemplo n.º 12
0
        private void DoContextHelp()
        {
            // Open CMake help for the command, standard variables, or standard module
            // at the caret.
            int line;
            int col;

            CMakeParsing.TokenData tokenData;
            if (TextView != null &&
                TextView.GetCaretPos(out line, out col) == VSConstants.S_OK &&
                CMakeParsing.ParseForToken(Source.GetLines(), line, col, out tokenData))
            {
                string   text      = Source.GetText(tokenData.TokenInfo.ToTextSpan(line));
                string[] htmlFiles = null;
                switch ((CMakeToken)tokenData.TokenInfo.Token)
                {
                case CMakeToken.Keyword:
                    if (!tokenData.InParens)
                    {
                        if (CMakeKeywords.IsDeprecated(CMakeKeywords.GetCommandId(text)))
                        {
                            htmlFiles = new string[]
                            {
                                "html\\command\\" + text.ToLower() + ".html",
                                "cmake-compatcommands.html#command:" + text.ToLower()
                            };
                        }
                        else
                        {
                            htmlFiles = new string[]
                            {
                                "html\\command\\" + text.ToLower() + ".html",
                                "cmake-commands.html#command:" + text.ToLower()
                            };
                        }
                    }
                    break;

                case CMakeToken.Variable:
                    if (CMakeVariableDeclarations.IsStandardVariable(text,
                                                                     CMakeVariableType.Variable))
                    {
                        htmlFiles = new string[]
                        {
                            "html\\variable\\" + text + ".html",
                            "cmake-variables.html#variable:" + text
                        };
                    }
                    break;

                case CMakeToken.Identifier:
                    if (tokenData.Command == CMakeCommandId.Include)
                    {
                        htmlFiles = new string[]
                        {
                            "html\\module\\" + text + ".html",
                            "cmake-modules.html#module:" + text
                        };
                    }
                    else if (tokenData.Command == CMakeCommandId.FindPackage)
                    {
                        htmlFiles = new string[]
                        {
                            "html\\module\\Find" + text + ".html",
                            "cmake-modules.html#module:Find" + text
                        };
                    }
                    break;
                }
                if (htmlFiles != null)
                {
                    CMakePackage.Instance.OpenCMakeHelpPage(htmlFiles);
                }
            }
        }
Exemplo n.º 13
0
        private string GetCurrentTokenFileName(out string extraSearchPath)
        {
            // Obtain the name of the file referenced by the current token if there is
            // one or null otherwise.
            int line;
            int col;

            extraSearchPath = null;
            if (TextView == null ||
                TextView.GetCaretPos(out line, out col) != VSConstants.S_OK)
            {
                return(null);
            }
            TokenInfo tokenInfo = Source.GetTokenInfo(line, col);

            if (tokenInfo == null ||
                (tokenInfo.Token != (int)CMakeToken.FileName &&
                 tokenInfo.Token != (int)CMakeToken.Identifier))
            {
                return(null);
            }
            string text = Source.GetText(tokenInfo.ToTextSpan(line));

            if (string.IsNullOrEmpty(text))
            {
                return(null);
            }

            // If the string specifies a file name with an extension, just return it
            // regardless or where it is found.
            if (tokenInfo.Token == (int)CMakeToken.FileName &&
                text.IndexOf('.') >= 0)
            {
                return(text);
            }

            // An identifier or path may reference a file if appears as a parameter to
            // one of certain commands, such as INCLUDE or FIND_PACKAGE.  Parse to find
            // the command to which the token is a parameter, if any, and handle it
            // accordingly.
            CMakeParsing.TokenData tokenData;
            if (!CMakeParsing.ParseForToken(Source.GetLines(), line, col,
                                            out tokenData) || !tokenData.InParens)
            {
                return(null);
            }
            switch (tokenData.Command)
            {
            case CMakeCommandId.Include:
                if (tokenData.ParameterIndex == 0)
                {
                    extraSearchPath = CMakePath.FindCMakeModules();
                    return(string.Format("{0}.cmake",
                                         Source.GetText(tokenInfo.ToTextSpan(line))));
                }
                break;

            case CMakeCommandId.FindPackage:
                if (tokenData.ParameterIndex == 0)
                {
                    extraSearchPath = CMakePath.FindCMakeModules();
                    return(string.Format("Find{0}.cmake",
                                         Source.GetText(tokenInfo.ToTextSpan(line))));
                }
                break;

            case CMakeCommandId.AddSubdirectory:
                if (tokenData.ParameterIndex == 0)
                {
                    return(Path.Combine(Source.GetText(tokenInfo.ToTextSpan(line)),
                                        "CMakeLists.txt"));
                }
                break;
            }
            return(null);
        }