# Buggy code
def _add_symbols(self, nestedName, templateDecls, declaration, docname):
    # type: (ASTNestedName, List[Any], ASTDeclaration, unicode) -> Symbol
    # Used for adding a whole path of symbols, where the last may or may not
    # be an actual declaration.

    if Symbol.debug_lookup:
        print("_add_symbols:")
        print("   tdecls:", templateDecls)
        print("   nn:    ", nestedName)
        print("   decl:  ", declaration)
        print("   doc:   ", docname)

    def onMissingQualifiedSymbol(parentSymbol, identOrOp, templateParams, templateArgs):
        # type: (Symbol, Union[ASTIdentifier, ASTOperator], Any, ASTTemplateArgs) -> Symbol
        if Symbol.debug_lookup:
            print("   _add_symbols, onMissingQualifiedSymbol:")
            print("      templateParams:", templateParams)
            print("      identOrOp:     ", identOrOp)
            print("      templateARgs:  ", templateArgs)
        return Symbol(
            parent=parentSymbol,
            identOrOp=identOrOp,
            templateParams=templateParams,
            templateArgs=templateArgs,
            declaration=None,
            docname=None,
        )

    lookupResult = self._symbol_lookup(
        nestedName,
        templateDecls,
        onMissingQualifiedSymbol,
        strictTemplateParamArgLists=True,
        ancestorLookupType=None,
        templateShorthand=False,
        matchSelf=False,
        recurseInAnon=True,
        correctPrimaryTemplateArgs=True,
    )
    assert (
        lookupResult is not None
    )  # we create symbols all the way, so that can't happen
    symbols = list(lookupResult.symbols)
    if len(symbols) == 0:
        if Symbol.debug_lookup:
            print("   _add_symbols, result, no symbol:")
            print("      templateParams:", lookupResult.templateParams)
            print("      identOrOp:     ", lookupResult.identOrOp)
            print("      templateArgs:  ", lookupResult.templateArgs)
            print("      declaration:   ", declaration)
            print("      docname:       ", docname)
        symbol = Symbol(
            parent=lookupResult.parentSymbol,
            identOrOp=lookupResult.identOrOp,
            templateParams=lookupResult.templateParams,
            templateArgs=lookupResult.templateArgs,
            declaration=declaration,
            docname=docname,
        )
        return symbol

    if Symbol.debug_lookup:
        print("   _add_symbols, result, symbols:")
        print("      number symbols:", len(symbols))

    if not declaration:
        if Symbol.debug_lookup:
            print("      no delcaration")
        # good, just a scope creation
        # TODO: what if we have more than one symbol?
        return symbols[0]

    noDecl = []
    withDecl = []
    dupDecl = []
    for s in symbols:
        if s.declaration is None:
            noDecl.append(s)
        elif s.isRedeclaration:
            dupDecl.append(s)
        else:
            withDecl.append(s)
    if Symbol.debug_lookup:
        print("      #noDecl:  ", len(noDecl))
        print("      #withDecl:", len(withDecl))
        print("      #dupDecl: ", len(dupDecl))
    if len(dupDecl) > 0:
        assert len(withDecl) > 0
    # assert len(noDecl) <= 1  # we should fill in symbols when they are there
    # TODO: enable assertion when we at some point find out how to do cleanup
    # With partial builds we may start with a large symbol tree stripped of declarations.

    # First check if one of those with a declaration matches.
    # If it's a function, we need to compare IDs,
    # otherwise there should be only one symbol with a declaration.
    def makeCandSymbol():
        if Symbol.debug_lookup:
            print("      begin: creating candidate symbol")
        symbol = Symbol(
            parent=lookupResult.parentSymbol,
            identOrOp=lookupResult.identOrOp,
            templateParams=lookupResult.templateParams,
            templateArgs=lookupResult.templateArgs,
            declaration=declaration,
            docname=docname,
        )
        if Symbol.debug_lookup:
            print("      end:   creating candidate symbol")
        return symbol

    if len(withDecl) == 0:
        candSymbol = None
    else:
        candSymbol = makeCandSymbol()

        def handleDuplicateDeclaration(symbol, candSymbol):
            if Symbol.debug_lookup:
                print("      redeclaration")
            # Redeclaration of the same symbol.
            # Let the new one be there, but raise an error to the client
            # so it can use the real symbol as subscope.
            # This will probably result in a duplicate id warning.
            candSymbol.isRedeclaration = True
            raise _DuplicateSymbolError(symbol, declaration)

        if declaration.objectType != "function":
            assert len(withDecl) <= 1
            handleDuplicateDeclaration(withDecl[0], candSymbol)
            # (not reachable)

        # a function, so compare IDs
        candId = declaration.get_newest_id()
        if Symbol.debug_lookup:
            print("      candId:", candId)
        for symbol in withDecl:
            oldId = symbol.declaration.get_newest_id()
            if Symbol.debug_lookup:
                print("      oldId: ", oldId)
            if candId == oldId:
                handleDuplicateDeclaration(symbol, candSymbol)
                # (not reachable)
        # no candidate symbol found with matching ID
    # if there is an empty symbol, fill that one
    if len(noDecl) == 0:
        if Symbol.debug_lookup:
            print(
                "      no match, no empty, candSybmol is not None?:",
                candSymbol is not None,
            )  # NOQA
        if candSymbol is not None:
            return candSymbol
        else:
            return makeCandSymbol()
    else:
        if Symbol.debug_lookup:
            print(
                "      no match, but fill an empty declaration, candSybmol is not None?:",
                candSymbol is not None,
            )  # NOQA
        if candSymbol is not None:
            candSymbol.remove()
        # assert len(noDecl) == 1
        # TODO: enable assertion when we at some point find out how to do cleanup
        # for now, just take the first one, it should work fine ... right?
        symbol = noDecl[0]
        # If someone first opened the scope, and then later
        # declares it, e.g,
        # .. namespace:: Test
        # .. namespace:: nullptr
        # .. class:: Test
        symbol._fill_empty(declaration, docname)
        return symbol


# Traceback (AssertionError)
# Sphinx version: 1.8.1
# Python version: 2.7.12 (CPython)
# Docutils version: 0.14
# Jinja2 version: 2.10
# Last messages:
#   Running Sphinx v1.8.1
#   building [mo]: targets for 0 po files that are out of date
#   building [html]: targets for 6 source files that are out of date
#   updating environment:
#   6 added, 0 changed, 0 removed
#   reading sources... [ 16%] contents
#   reading sources... [ 33%] output/class/classTemplateClass
#   reading sources... [ 50%] output/class/classTemplateClass_3_01T_01_5_01_4
#   reading sources... [ 66%] output/classlist
#   reading sources... [ 83%] output/file/test_8cpp
# Loaded extensions:
#   sphinx.ext.mathjax (1.8.1) from c:\anaconda2\lib\site-packages\sphinx\ext\mathjax.pyc
#   alabaster (0.7.10) from c:\anaconda2\lib\site-packages\alabaster\__init__.pyc
#   breathe (4.10.0) from c:\anaconda2\lib\site-packages\breathe\__init__.pyc
Traceback (most recent call last):
File "c:\anaconda2\lib\site-packages\sphinx\cmd\build.py", line 304, in build_main
app.build(args.force_all, filenames)
File "c:\anaconda2\lib\site-packages\sphinx\application.py", line 341, in build
self.builder.build_update()
File "c:\anaconda2\lib\site-packages\sphinx\builders\__init__.py", line 347, in build_update
len(to_build))
File "c:\anaconda2\lib\site-packages\sphinx\builders\__init__.py", line 360, in build
updated_docnames = set(self.read())
File "c:\anaconda2\lib\site-packages\sphinx\builders\__init__.py", line 468, in read
self._read_serial(docnames)
File "c:\anaconda2\lib\site-packages\sphinx\builders\__init__.py", line 490, in _read_serial
self.read_doc(docname)
File "c:\anaconda2\lib\site-packages\sphinx\builders\__init__.py", line 534, in read_doc
doctree = read_doc(self.app, self.env, self.env.doc2path(docname))
File "c:\anaconda2\lib\site-packages\sphinx\io.py", line 318, in read_doc
pub.publish()
File "c:\anaconda2\lib\site-packages\docutils\core.py", line 217, in publish
self.settings)
File "c:\anaconda2\lib\site-packages\docutils\readers\__init__.py", line 72, in read
self.parse()
File "c:\anaconda2\lib\site-packages\docutils\readers\__init__.py", line 78, in parse
self.parser.parse(self.input, document)
File "c:\anaconda2\lib\site-packages\sphinx\parsers.py", line 88, in parse
self.statemachine.run(inputstring, document, inliner=self.inliner)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 171, in run
input_source=document['source'])
File "c:\anaconda2\lib\site-packages\docutils\statemachine.py", line 239, in run
context, state, transitions)
File "c:\anaconda2\lib\site-packages\docutils\statemachine.py", line 460, in check_line
return method(match, context, next_state)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 2753, in underline
self.section(title, source, style, lineno - 1, messages)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 327, in section
self.new_subsection(title, lineno, messages)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 395, in new_subsection
node=section_node, match_titles=True)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 282, in nested_parse
node=node, match_titles=match_titles)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 196, in run
results = StateMachineWS.run(self, input_lines, input_offset)
File "c:\anaconda2\lib\site-packages\docutils\statemachine.py", line 239, in run
context, state, transitions)
File "c:\anaconda2\lib\site-packages\docutils\statemachine.py", line 460, in check_line
return method(match, context, next_state)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 2326, in explicit_markup
nodelist, blank_finish = self.explicit_construct(match)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 2338, in explicit_construct
return method(self, expmatch)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 2081, in directive
directive_class, match, type_name, option_presets)
File "c:\anaconda2\lib\site-packages\docutils\parsers\rst\states.py", line 2130, in run_directive
result = directive_instance.run()
File "c:\anaconda2\lib\site-packages\breathe\directive\file.py", line 91, in run
return self.handle_contents(file_, project_info)
File "c:\anaconda2\lib\site-packages\breathe\directive\file.py", line 61, in handle_contents
node_list.extend(object_renderer.render(node_stack[0], context))
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 1304, in render
result = method(self, node)
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 630, in visit_compounddef
nodelist.extend(self.render_iterable(node.innerclass))
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 1314, in render_iterable
output.extend(self.render(entry))
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 1304, in render
result = method(self, node)
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 907, in visit_ref
return self.visit_compound(node, False, get_node_info=get_node_info)
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 508, in visit_compound
name, kind)
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 486, in render_signature
nodes = self.run_domain_directive(kind, self.context.directive_args[1], augment=augment)
File "c:\anaconda2\lib\site-packages\breathe\renderer\sphinxrenderer.py", line 351, in run_domain_directive
nodes = domain_directive.run()
File "c:\anaconda2\lib\site-packages\sphinx\domains\cpp.py", line 6312, in run
return ObjectDescription.run(self)
File "c:\anaconda2\lib\site-packages\sphinx\directives\__init__.py", line 161, in run
name = self.handle_signature(sig, signode)
File "c:\anaconda2\lib\site-packages\sphinx\domains\cpp.py", line 6332, in handle_signature
symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
File "c:\anaconda2\lib\site-packages\sphinx\domains\cpp.py", line 4151, in add_declaration
return self._add_symbols(nestedName, templateDecls, declaration, docname)
File "c:\anaconda2\lib\site-packages\sphinx\domains\cpp.py", line 4060, in _add_symbols
assert len(withDecl) <= 1
AssertionError

# Fixed code
def _add_symbols(self, nestedName, templateDecls, declaration, docname):
    # type: (ASTNestedName, List[Any], ASTDeclaration, unicode) -> Symbol
    # Used for adding a whole path of symbols, where the last may or may not
    # be an actual declaration.

    if Symbol.debug_lookup:
        print("_add_symbols:")
        print("   tdecls:", templateDecls)
        print("   nn:    ", nestedName)
        print("   decl:  ", declaration)
        print("   doc:   ", docname)

    def onMissingQualifiedSymbol(parentSymbol, identOrOp, templateParams, templateArgs):
        # type: (Symbol, Union[ASTIdentifier, ASTOperator], Any, ASTTemplateArgs) -> Symbol
        if Symbol.debug_lookup:
            print("   _add_symbols, onMissingQualifiedSymbol:")
            print("      templateParams:", templateParams)
            print("      identOrOp:     ", identOrOp)
            print("      templateARgs:  ", templateArgs)
        return Symbol(
            parent=parentSymbol,
            identOrOp=identOrOp,
            templateParams=templateParams,
            templateArgs=templateArgs,
            declaration=None,
            docname=None,
        )

    lookupResult = self._symbol_lookup(
        nestedName,
        templateDecls,
        onMissingQualifiedSymbol,
        strictTemplateParamArgLists=True,
        ancestorLookupType=None,
        templateShorthand=False,
        matchSelf=False,
        recurseInAnon=True,
        correctPrimaryTemplateArgs=True,
    )
    assert (
        lookupResult is not None
    )  # we create symbols all the way, so that can't happen
    symbols = list(lookupResult.symbols)
    if len(symbols) == 0:
        if Symbol.debug_lookup:
            print("   _add_symbols, result, no symbol:")
            print("      templateParams:", lookupResult.templateParams)
            print("      identOrOp:     ", lookupResult.identOrOp)
            print("      templateArgs:  ", lookupResult.templateArgs)
            print("      declaration:   ", declaration)
            print("      docname:       ", docname)
        symbol = Symbol(
            parent=lookupResult.parentSymbol,
            identOrOp=lookupResult.identOrOp,
            templateParams=lookupResult.templateParams,
            templateArgs=lookupResult.templateArgs,
            declaration=declaration,
            docname=docname,
        )
        return symbol

    if Symbol.debug_lookup:
        print("   _add_symbols, result, symbols:")
        print("      number symbols:", len(symbols))

    if not declaration:
        if Symbol.debug_lookup:
            print("      no delcaration")
        # good, just a scope creation
        # TODO: what if we have more than one symbol?
        return symbols[0]

    noDecl = []
    withDecl = []
    dupDecl = []
    for s in symbols:
        if s.declaration is None:
            noDecl.append(s)
        elif s.isRedeclaration:
            dupDecl.append(s)
        else:
            withDecl.append(s)
    if Symbol.debug_lookup:
        print("      #noDecl:  ", len(noDecl))
        print("      #withDecl:", len(withDecl))
        print("      #dupDecl: ", len(dupDecl))
    # With partial builds we may start with a large symbol tree stripped of declarations.
    # Essentially any combination of noDecl, withDecl, and dupDecls seems possible.
    # TODO: make partial builds fully work. What should happen when the primary symbol gets
    #  deleted, and other duplicates exist? The full document should probably be rebuild.

    # First check if one of those with a declaration matches.
    # If it's a function, we need to compare IDs,
    # otherwise there should be only one symbol with a declaration.
    def makeCandSymbol():
        if Symbol.debug_lookup:
            print("      begin: creating candidate symbol")
        symbol = Symbol(
            parent=lookupResult.parentSymbol,
            identOrOp=lookupResult.identOrOp,
            templateParams=lookupResult.templateParams,
            templateArgs=lookupResult.templateArgs,
            declaration=declaration,
            docname=docname,
        )
        if Symbol.debug_lookup:
            print("      end:   creating candidate symbol")
        return symbol

    if len(withDecl) == 0:
        candSymbol = None
    else:
        candSymbol = makeCandSymbol()

        def handleDuplicateDeclaration(symbol, candSymbol):
            if Symbol.debug_lookup:
                print("      redeclaration")
            # Redeclaration of the same symbol.
            # Let the new one be there, but raise an error to the client
            # so it can use the real symbol as subscope.
            # This will probably result in a duplicate id warning.
            candSymbol.isRedeclaration = True
            raise _DuplicateSymbolError(symbol, declaration)

        if declaration.objectType != "function":
            assert len(withDecl) <= 1
            handleDuplicateDeclaration(withDecl[0], candSymbol)
            # (not reachable)

        # a function, so compare IDs
        candId = declaration.get_newest_id()
        if Symbol.debug_lookup:
            print("      candId:", candId)
        for symbol in withDecl:
            oldId = symbol.declaration.get_newest_id()
            if Symbol.debug_lookup:
                print("      oldId: ", oldId)
            if candId == oldId:
                handleDuplicateDeclaration(symbol, candSymbol)
                # (not reachable)
        # no candidate symbol found with matching ID
    # if there is an empty symbol, fill that one
    if len(noDecl) == 0:
        if Symbol.debug_lookup:
            print(
                "      no match, no empty, candSybmol is not None?:",
                candSymbol is not None,
            )  # NOQA
        if candSymbol is not None:
            return candSymbol
        else:
            return makeCandSymbol()
    else:
        if Symbol.debug_lookup:
            print(
                "      no match, but fill an empty declaration, candSybmol is not None?:",
                candSymbol is not None,
            )  # NOQA
        if candSymbol is not None:
            candSymbol.remove()
        # assert len(noDecl) == 1
        # TODO: enable assertion when we at some point find out how to do cleanup
        # for now, just take the first one, it should work fine ... right?
        symbol = noDecl[0]
        # If someone first opened the scope, and then later
        # declares it, e.g,
        # .. namespace:: Test
        # .. namespace:: nullptr
        # .. class:: Test
        symbol._fill_empty(declaration, docname)
        return symbol