C++, fix direct lookup problem

Also clarify documentation regarding cross-references involving templates.

See also sphinx-doc/sphinx#2057
This commit is contained in:
Jakob Lykke Andersen 2018-08-11 10:30:10 +02:00
parent 0af74a76dc
commit 4397606d03
3 changed files with 48 additions and 27 deletions

View File

@ -172,6 +172,8 @@ Features added
* C++, add support for anonymous entities using names staring with ``@``. * C++, add support for anonymous entities using names staring with ``@``.
Fixes #3593 and #2683. Fixes #3593 and #2683.
* #5147: C++, add support for (most) character literals. * #5147: C++, add support for (most) character literals.
* C++, cross-referencing entities inside primary templates is supported,
and now properly documented.
* #3606: MathJax should be loaded with async attribute * #3606: MathJax should be loaded with async attribute
* html: Output ``canonical_url`` metadata if :confval:`html_baseurl` set (refs: * html: Output ``canonical_url`` metadata if :confval:`html_baseurl` set (refs:
#4193) #4193)

View File

@ -1033,19 +1033,25 @@ Assume the following declarations.
Inner Inner
In general the reference must include the template parameter declarations, In general the reference must include the template parameter declarations,
e.g., ``template\<typename TOuter> Wrapper::Outer`` and template arguments for the prefix of qualified names. For example:
(:cpp:class:`template\<typename TOuter> Wrapper::Outer`). Currently the lookup
only succeed if the template parameter identifiers are equal strings. That is,
``template\<typename UOuter> Wrapper::Outer`` will not work.
The inner class template cannot be directly referenced, unless the current - ``template\<typename TOuter> Wrapper::Outer``
namespace is changed or the following shorthand is used. If a template (:cpp:class:`template\<typename TOuter> Wrapper::Outer`)
parameter list is omitted, then the lookup will assume either a template or a - ``template\<typename TOuter> template\<typename TInner> Wrapper::Outer<TOuter>::Inner``
non-template, but not a partial template specialisation. This means the (:cpp:class:`template\<typename TOuter> template\<typename TInner> Wrapper::Outer<TOuter>::Inner`)
following references work.
- ``Wrapper::Outer`` (:cpp:class:`Wrapper::Outer`) Currently the lookup only succeed if the template parameter identifiers are equal strings.
- ``Wrapper::Outer::Inner`` (:cpp:class:`Wrapper::Outer::Inner`) That is, ``template\<typename UOuter> Wrapper::Outer`` will not work.
As a shorthand notation, if a template parameter list is omitted,
then the lookup will assume either a primary template or a non-template,
but not a partial template specialisation.
This means the following references work as well:
- ``Wrapper::Outer``
(:cpp:class:`Wrapper::Outer`)
- ``Wrapper::Outer::Inner``
(:cpp:class:`Wrapper::Outer::Inner`)
- ``template\<typename TInner> Wrapper::Outer::Inner`` - ``template\<typename TInner> Wrapper::Outer::Inner``
(:cpp:class:`template\<typename TInner> Wrapper::Outer::Inner`) (:cpp:class:`template\<typename TInner> Wrapper::Outer::Inner`)

View File

@ -3634,8 +3634,9 @@ class Symbol(object):
return ASTNestedName(names, templates, rooted=False) return ASTNestedName(names, templates, rooted=False)
def _find_named_symbol(self, identOrOp, templateParams, templateArgs, def _find_named_symbol(self, identOrOp, templateParams, templateArgs,
templateShorthand, matchSelf, recurseInAnon): templateShorthand, matchSelf, recurseInAnon,
# type: (Any, Any, Any, Any, bool, bool) -> Symbol correctPrimaryTemplateArgs):
# type: (Any, Any, Any, Any, bool, bool, bool) -> Symbol
def isSpecialization(): def isSpecialization():
# the names of the template parameters must be given exactly as args # the names of the template parameters must be given exactly as args
@ -3658,12 +3659,13 @@ class Symbol(object):
if paramName != argName: if paramName != argName:
return True return True
return False return False
if templateParams is not None and templateArgs is not None: if correctPrimaryTemplateArgs:
# If both are given, but it's not a specialization, then do lookup as if if templateParams is not None and templateArgs is not None:
# there is no argument list. # If both are given, but it's not a specialization, then do lookup as if
# For example: template<typename T> int A<T>::var; # there is no argument list.
if not isSpecialization(): # For example: template<typename T> int A<T>::var;
templateArgs = None if not isSpecialization():
templateArgs = None
def matches(s): def matches(s):
if s.identOrOp != identOrOp: if s.identOrOp != identOrOp:
@ -3722,7 +3724,8 @@ class Symbol(object):
templateArgs, templateArgs,
templateShorthand=False, templateShorthand=False,
matchSelf=False, matchSelf=False,
recurseInAnon=True) recurseInAnon=True,
correctPrimaryTemplateArgs=True)
if symbol is None: if symbol is None:
symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp, symbol = Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams, templateParams=templateParams,
@ -3746,7 +3749,8 @@ class Symbol(object):
templateArgs, templateArgs,
templateShorthand=False, templateShorthand=False,
matchSelf=False, matchSelf=False,
recurseInAnon=True) recurseInAnon=True,
correctPrimaryTemplateArgs=False)
if symbol: if symbol:
if not declaration: if not declaration:
# good, just a scope creation # good, just a scope creation
@ -3797,7 +3801,8 @@ class Symbol(object):
templateArgs=otherChild.templateArgs, templateArgs=otherChild.templateArgs,
templateShorthand=False, templateShorthand=False,
matchSelf=False, matchSelf=False,
recurseInAnon=False) recurseInAnon=False,
correctPrimaryTemplateArgs=False)
if ourChild is None: if ourChild is None:
# TODO: hmm, should we prune by docnames? # TODO: hmm, should we prune by docnames?
self._children.append(otherChild) self._children.append(otherChild)
@ -3860,7 +3865,8 @@ class Symbol(object):
templateParams, templateArgs, templateParams, templateArgs,
templateShorthand=False, templateShorthand=False,
matchSelf=False, matchSelf=False,
recurseInAnon=False) recurseInAnon=False,
correctPrimaryTemplateArgs=False)
if not s: if not s:
return None return None
return s return s
@ -3911,7 +3917,8 @@ class Symbol(object):
templateParams, templateArgs, templateParams, templateArgs,
templateShorthand=templateShorthand, templateShorthand=templateShorthand,
matchSelf=matchSelf, matchSelf=matchSelf,
recurseInAnon=recurseInAnon) recurseInAnon=recurseInAnon,
correctPrimaryTemplateArgs=False)
if symbol is not None: if symbol is not None:
return symbol return symbol
# try without template params and args # try without template params and args
@ -3919,7 +3926,8 @@ class Symbol(object):
None, None, None, None,
templateShorthand=templateShorthand, templateShorthand=templateShorthand,
matchSelf=matchSelf, matchSelf=matchSelf,
recurseInAnon=recurseInAnon) recurseInAnon=recurseInAnon,
correctPrimaryTemplateArgs=False)
return symbol return symbol
else: else:
identOrOp = name.identOrOp identOrOp = name.identOrOp
@ -3933,9 +3941,13 @@ class Symbol(object):
templateParams, templateArgs, templateParams, templateArgs,
templateShorthand=templateShorthand, templateShorthand=templateShorthand,
matchSelf=matchSelf, matchSelf=matchSelf,
recurseInAnon=recurseInAnon) recurseInAnon=recurseInAnon,
correctPrimaryTemplateArgs=True)
if symbol is None: if symbol is None:
# TODO: maybe search without template args # TODO: Maybe search without template args?
# Though, the correctPrimaryTemplateArgs above does
# that for primary templates.
# Is there another case where it would be good?
return None return None
# We have now matched part of a nested name, and need to match more # We have now matched part of a nested name, and need to match more
# so even if we should matchSelf before, we definitely shouldn't # so even if we should matchSelf before, we definitely shouldn't
@ -6343,6 +6355,7 @@ class CPPDomain(Domain):
if not parentSymbol: if not parentSymbol:
print("Target: ", target) print("Target: ", target)
print("ParentKey: ", parentKey) print("ParentKey: ", parentKey)
print(rootSymbol.dump(1))
assert parentSymbol # should be there assert parentSymbol # should be there
else: else:
parentSymbol = rootSymbol parentSymbol = rootSymbol